package com.googlecode.gwtbb.server.intermediate.forum;

import com.googlecode.gwtbb.client.shared.GwtbbSmess;
import com.googlecode.gwtbb.client.shared.entity.forum.Forum;
import com.googlecode.gwtbb.client.shared.entity.forum.Post;
import com.googlecode.gwtbb.client.shared.entity.forum.PostBase;
import com.googlecode.gwtbb.client.shared.entity.forum.PostSnap;
import com.googlecode.gwtbb.client.shared.entity.user.User;
import com.googlecode.gwtbb.client.shared.remote.forum.CreatePostBean;
import com.googlecode.gwtbb.client.shared.validation.Failure;
import com.googlecode.gwtbb.client.shared.validation.FieldId;
import com.googlecode.gwtbb.server.dao.forum.ForumDao;
import com.googlecode.gwtbb.server.dao.forum.PostDao;
import com.googlecode.gwtbb.server.dao.forum.PostSnapDao;
import com.googlecode.gwtbb.server.intermediate.Meta;
import com.googlecode.gwtbb.server.intermediate.user.PrivilegeChecker;

import java.util.Date;
import java.util.Map;

/**
 * @author Abraham Grief
 * @version $Id$
 * @since Aug 6, 2008
 */
public class PostVip {
	private ForumDao forumDao;
	private PostDao postDao;
	private PostSnapDao postSnapDao;
	private PrivilegeChecker privilegeChecker;

	public ForumDao getForumDao() {
		return forumDao;
	}

	public void setForumDao(ForumDao forumDao) {
		this.forumDao = forumDao;
	}

	public PostDao getPostDao() {
		return postDao;
	}

	public void setPostDao(PostDao postDao) {
		this.postDao = postDao;
	}

	public PostSnapDao getPostSnapDao() {
		return postSnapDao;
	}

	public void setPostSnapDao(PostSnapDao postSnapDao) {
		this.postSnapDao = postSnapDao;
	}

	public PrivilegeChecker getPrivilegeChecker() {
		return privilegeChecker;
	}

	public void setPrivilegeChecker(PrivilegeChecker privilegeChecker) {
		this.privilegeChecker = privilegeChecker;
	}

	public boolean instantiate(CreateState state, Date snapDate, String process) {
		if (state.isInstantiatable()) {
			Long postId = postDao.generateId();
			if (state.threadId == null)
				state.threadId = postId;

			state.post = new Post(postId, state.threadId, state.createPostBean.getForumId(), state.actor.getId(), state.createPostBean.getSubject(), state.createPostBean.getBody(), snapDate, snapDate);
			state.postSnap = newPostSnap(state.post, state.actor, process);
		}
		return state.isPersistable();
	}

	public boolean instantiatePersist(CreateState state, Date snapDate, String process) {
		return instantiate(state, snapDate, process) && persist(state);
	}

	public boolean persist(CreateState state) {
		if (state.isPersistable()) {
			postDao.createPreIdentified(state.post);
			postSnapDao.create(state.postSnap);
			return state.completed = true;
		}
		return false;
	}

	public CreateState validate(Map<FieldId, Failure> failures, Long userId, String sessionId, CreatePostBean createPostBean) {
		CreateState retVal = new CreateState();
		if (createPostBean != null) {
			createPostBean.validate(failures, 0);
			retVal.forum = forumDao.select(createPostBean.getForumId());
			if (retVal.forum == null || retVal.forum.isDeleted())
				failures.put(null, new Failure(GwtbbSmess.instance().invalidForum()));
			retVal.createPostBean = createPostBean;
			retVal.threadId = createPostBean.getThreadId();
			retVal.actor = privilegeChecker.checkPrivilege(failures, userId, sessionId, User.PrivilegeLevel.UNVERIFIED);
			retVal.failed = !failures.isEmpty();
		}
		return retVal;
	}

	private static PostSnap newPostSnap(Post post, User actor, String process) {
		return Meta.instantiateSnapshot(PostSnap.class, post, PostBase.PROPERTIES, actor.getId(), process);
	}

	public static class CreateState {
		protected boolean completed;
		protected boolean failed;
		protected CreatePostBean createPostBean;
		protected User actor;
		protected Long threadId;
		protected Post post;
		protected PostSnap postSnap;
		protected Forum forum;

		public Forum getForum() {
			return forum;
		}

		public Post getPost() {
			return post;
		}

		public boolean isCompleted() {
			return completed;
		}

		public boolean isFailed() {
			return failed;
		}

		public boolean isInstantiatable() {
			return !failed;
		}

		public boolean isPersistable() {
			return !failed;
		}
	}
}
